package com.hn.common.utils.ding;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.*;
import com.dingtalk.api.response.*;
import com.hn.common.exception.DingException;
import com.hn.common.utils.ding.process.Process;
import com.hn.common.utils.ding.process.ProcessForm;
import com.hn.common.utils.ding.process.ProcessFormType;
import com.hn.common.utils.ding.process.ProcessListIdsVo;
import com.hn.common.utils.ding.process.ProcessModel;
import com.taobao.api.ApiException;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 审批流工具类
 *
 * @author admin
 */
public class DingProcessInstanceUtil {
    private static final Log log = LogFactory.get();

    public static void main(String[] args) throws Exception {
 /*       DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/workrecord/getbyuserid");
        OapiWorkrecordGetbyuseridRequest req = new OapiWorkrecordGetbyuseridRequest();
        req.setUserid("0502101558117240531");
        req.setOffset(0L);
        req.setLimit(50L);
        req.setStatus(0L);
        OapiWorkrecordGetbyuseridResponse rsp = client.execute(req, AccessTokenUtil.getToken());
        System.out.println(rsp.getBody());*/

        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/processinstance/get");
        OapiProcessinstanceGetRequest request = new OapiProcessinstanceGetRequest();
        request.setProcessInstanceId("15558dda-5a5a-494f-9126-cf9ab9818391");
        OapiProcessinstanceGetResponse response = client.execute(request, AccessTokenUtil.getToken());
        System.out.println(response.getBody());
       /* DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/process/listbyuserid");
        OapiProcessListbyuseridRequest request = new OapiProcessListbyuseridRequest();
//        request.setUserid("manager7078");
        request.setOffset(0L);
        request.setSize(100L);
        OapiProcessListbyuseridResponse response = client.execute(request, AccessTokenUtil.getToken());
        System.out.println(response.getResult());*/

        /*ProcessListIdsVo processListIdsVo = new ProcessListIdsVo();
        processListIdsVo.setProcessCode(DingConstant.PROCESS_CODE);
        processListIdsVo.setStartTime(DateUtils.parseDate("2018-06-27 8:00:00").getTime());
        processListIdsVo.setEndTime(System.currentTimeMillis());
        processListIdsVo.setCursor(0L);
        processListIdsVo.setSize(10L);
//      processListIdsVo.setUserIdList("manager447");
        OapiProcessinstanceListidsResponse.PageResult result = listids(processListIdsVo);

        List<String> list = result.getList();
        for (String processId : list) {
            OapiProcessinstanceGetResponse.ProcessInstanceTopVo processInstanceTopVo = get(processId);
            String title = processInstanceTopVo.getTitle();
            String originatorUserid = processInstanceTopVo.getOriginatorUserid();
            List<OapiProcessinstanceGetResponse.OperationRecordsVo> operationRecords = processInstanceTopVo.getOperationRecords();


            System.out.println(originatorUserid);
        }*/


        /*OapiProcessinstanceCreateRequest request = new OapiProcessinstanceCreateRequest();
        request.setProcessCode(DingConstant.PROCESS_CODE);

        ProcessForm processForm = new ProcessForm();
        processForm.put("请假类型","事假")
                .put("开始时间","2019-06-27 10:39")
                .put("结束时间","2019-06-29 10:39")
                .put("时长","5")
                .put("请假事由","测试请假事由2019-06-27 14：06");

        List<OapiProcessinstanceCreateRequest.FormComponentValueVo> formComponentValues = processForm.getList();
        request.setFormComponentValues(formComponentValues);
        request.setApprovers("manager447");
        request.setOriginatorUserId("manager447");
        request.setDeptId(-1L);
        request.setCcList("manager447");
        request.setCcPosition("FINISH");
        create(request);
        */
    }

    /**
     * 发起审批实例
     * @param request {@link OapiProcessinstanceCreateRequest}
     * @return ProcessInstanceId
     */
    public static String create(OapiProcessinstanceCreateRequest request) {
        String originatorUserId = request.getOriginatorUserId();
        if(StrUtil.isBlank(originatorUserId)){
            throw new DingException("当前用户未绑定钉钉用户");
        }

        DefaultDingTalkClient client = new DefaultDingTalkClient(DingURLConstant.URL_PROCESSINSTANCE_START);
        OapiProcessinstanceCreateResponse response = null;
        try {
            response = client.execute(request, AccessTokenUtil.getToken());
        } catch (ApiException e) {
            throw new DingException("发起审批实例异常," + e.getErrMsg());
        }
        if (DingConstant.SUCCESS_CODE.equals(response.getErrcode())) {
            log.debug("发起审批实例 success,{}", response.getProcessInstanceId());
            log.debug("发起审批实例 success,{}", response.getParams());
            return response.getProcessInstanceId();
        }
        throw new DingException("发起审批实例异常," + response.getMsg());
    }

    /**
     * 获取审批实例详情
     * @param processInstanceId 审批实例ID
     * @return {@link OapiProcessinstanceGetResponse.ProcessInstanceTopVo}
     */
    public static OapiProcessinstanceGetResponse.ProcessInstanceTopVo get(String processInstanceId) {
        DingTalkClient client = new DefaultDingTalkClient(DingURLConstant.PROCESS_INSTANCE_GET);
        OapiProcessinstanceGetRequest request = new OapiProcessinstanceGetRequest();
        request.setProcessInstanceId(processInstanceId);
        OapiProcessinstanceGetResponse response = null;
        try {
            response = client.execute(request, AccessTokenUtil.getToken());
        } catch (ApiException e) {
            throw new DingException("获取审批实例详情异常," + e.getErrMsg());
        }
        if (DingConstant.SUCCESS_CODE.equals(response.getErrcode())) {
            log.debug("获取审批实例详情 success,{}", JSONUtil.toJsonStr(response.getProcessInstance()));
            return response.getProcessInstance();
        }
        throw new DingException("获取审批实例详情异常," + response.getMsg());
    }

    /**
     * 批量获取审批实例id
     *
     * @param processListIdsVo {@link ProcessListIdsVo}
     * @return {@link OapiProcessinstanceListidsResponse.PageResult}
     */
    public static OapiProcessinstanceListidsResponse.PageResult listIds(ProcessListIdsVo processListIdsVo) {
        DingTalkClient client = new DefaultDingTalkClient(DingURLConstant.LIST_IDS);
        OapiProcessinstanceListidsRequest req = new OapiProcessinstanceListidsRequest();
        req.setProcessCode(processListIdsVo.getProcessCode());
        req.setStartTime(processListIdsVo.getStartTime());
        req.setEndTime(processListIdsVo.getEndTime());
        req.setSize(processListIdsVo.getSize());
        req.setCursor(processListIdsVo.getCursor());
        // manager1,manager2
        req.setUseridList(processListIdsVo.getUserIdList());
        OapiProcessinstanceListidsResponse response = null;
        try {
            response = client.execute(req, AccessTokenUtil.getToken());
        } catch (ApiException e) {
            throw new DingException("批量获取审批实例id异常," + e.getErrMsg());
        }
        if (DingConstant.SUCCESS_CODE.equals(response.getErrcode())) {
            log.debug("批量获取审批实例id success,{}", JSONUtil.toJsonStr(response.getResult()));
            return response.getResult();
        }
        throw new DingException("批量获取审批实例id异常," + response.getMsg());
    }

    /**
     * 获取用户待审批数量
     *
     * @param userId 用户ID
     * @return 审批数量
     */
    public static Long gettodonum(String userId) {
        DingTalkClient client = new DefaultDingTalkClient(DingURLConstant.GET_TODO_NUM);
        OapiProcessGettodonumRequest req = new OapiProcessGettodonumRequest();
        req.setUserid(userId);
        OapiProcessGettodonumResponse response = null;
        try {
            response = client.execute(req, AccessTokenUtil.getToken());
        } catch (ApiException e) {
            throw new DingException("获取用户待审批数量异常," + e.getErrMsg());
        }
        if (DingConstant.SUCCESS_CODE.equals(response.getErrcode())) {
            log.debug("获取用户待审批数量success,{}", response.getCount());
            return response.getCount();
        }
        throw new DingException("获取用户待审批数量异常," + response.getMsg());
    }

    /**
     * 获取用户可见的审批模板
     *
     * @param userId 用户id
     * @param offset 分页游标，从0开始。根据返回结果里的next_cursor是否为空来判断是否还有下一页，且再次调用时offset设置成next_cursor的值
     * @param size   分页大小，最大可设置成100
     * @return {@link  OapiProcessListbyuseridResponse.HomePageProcessTemplateVo }
     */
    public static OapiProcessListbyuseridResponse.HomePageProcessTemplateVo listbyuserid(String userId, Long offset, Long size) {
        DingTalkClient client = new DefaultDingTalkClient(DingURLConstant.LIST_BY_USER_ID);
        OapiProcessListbyuseridRequest request = new OapiProcessListbyuseridRequest();
        request.setUserid(userId);
        request.setOffset(offset);
        request.setSize(size);
        OapiProcessListbyuseridResponse response = null;
        try {
            response = client.execute(request, AccessTokenUtil.getToken());
        } catch (ApiException e) {
            throw new DingException("获取用户可见的审批模板异常," + e.getErrMsg());
        }
        if (DingConstant.SUCCESS_CODE.equals(response.getErrcode())) {
            log.debug("获取用户可见的审批模板success,{}", response.getResult());
            return response.getResult();
        }
        throw new DingException("获取用户可见的审批模板异常," + response.getMsg());
    }

    /**
     * 获取审批钉盘空间信息
     * <p>
     * 返回结果:
     * {
     * "result":{
     * "space_id":12344546 审批钉盘空间id
     * },
     * "errcode":0,
     * "errmsg":"成功",
     * "success":true
     * }
     * @param userId 用户id
     * @return {@link OapiProcessinstanceCspaceInfoResponse.AppSpaceResponse}
     */
    public static OapiProcessinstanceCspaceInfoResponse.AppSpaceResponse cspaceInfo(String userId) {
        DingTalkClient client = new DefaultDingTalkClient(DingURLConstant.CSPACE_INFO);
        OapiProcessinstanceCspaceInfoRequest request = new OapiProcessinstanceCspaceInfoRequest();
        request.setUserId(userId);
        OapiProcessinstanceCspaceInfoResponse response = null;
        try {
            response = client.execute(request, AccessTokenUtil.getToken());
        } catch (ApiException e) {
            throw new DingException("获取审批钉盘空间信息异常," + e.getErrMsg());
        }
        if (DingConstant.SUCCESS_CODE.equals(response.getErrcode())) {
            log.debug("获取审批钉盘空间信息success,{}", response.getResult());
            return response.getResult();
        }
        throw new DingException("获取审批钉盘空间信息异常," + response.getMsg());
    }

    /**
     * 创建审批模板
     *
     * @param modelName   审批模板名称
     * @param processCode 审批模板的唯一码。在本接口中，如不传，表示新建一个模板。如传值了，表示更新所传值对应的审批模板
     * @param clazz       审批模板对象
     * @return processCode 审批模板code
     */
    public static String saveProcessModel(String modelName, String processCode, Class clazz) {
        DingTalkClient client = new DefaultDingTalkClient(DingURLConstant.SAVE_PROCESS_MODEL);
        OapiProcessSaveRequest request = new OapiProcessSaveRequest();
        OapiProcessSaveRequest.SaveProcessRequest saveProcessRequest = new OapiProcessSaveRequest.SaveProcessRequest();
        // 	是否允许表单在审批管理后台可编辑。true表示不可以
        saveProcessRequest.setDisableFormEdit(false);
        // 审批模板名称
        saveProcessRequest.setName(modelName);
        // 审批模板的唯一码。在本接口中，如不传，表示新建一个模板。如传值了，表示更新所传值对应的审批模板
        saveProcessRequest.setProcessCode(processCode);
        saveProcessRequest.setAgentid(Long.valueOf("769460355"));
        // 实体类转成模板
        ProcessModel processModel = ProcessModel.convert(clazz);

        List<OapiProcessSaveRequest.FormComponentVo> formComponentList = processModel.getFormComponentList();
        System.out.println(JSONUtil.toJsonStr(formComponentList));
        saveProcessRequest.setFormComponentList(formComponentList);
        request.setSaveProcessRequest(saveProcessRequest);

        OapiProcessSaveResponse response = null;
        try {
            response = client.execute(request, AccessTokenUtil.getToken());
        } catch (ApiException e) {
            throw new DingException("创建审批模板异常," + e.getErrMsg());
        }
        if (DingConstant.SUCCESS_CODE.equals(response.getErrcode())) {
            log.debug("创建审批模板success,{}", response.getResult());
            return response.getResult().getProcessCode();
        }
        throw new DingException("创建审批模板异常," + response.getMsg());
    }

    /**
     *  删除模板
     * @param processCode 审批模板code
     */
    public static void delProcessModel(String processCode) {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/process/delete");
        OapiProcessDeleteRequest req = new OapiProcessDeleteRequest();
        OapiProcessDeleteRequest.DeleteProcessRequest processRequest = new OapiProcessDeleteRequest.DeleteProcessRequest();
        processRequest.setAgentid(Long.valueOf(DingConstant.AGENTID));
        processRequest.setProcessCode(processCode);
        req.setRequest(processRequest);

        OapiProcessDeleteResponse response = null;
        try {
            response = client.execute(req, AccessTokenUtil.getToken());
        } catch (ApiException e) {
            log.debug("删除审批模板success,{}", e.getErrMsg());
        }
        if (DingConstant.SUCCESS_CODE.equals(response.getErrcode())) {
            log.debug("删除审批模板success,{}", response.getSuccess());
        }
    }

    public static ProcessForm convert(Object obj) {
        // 有数据时才处理 得到类的所有field.
        Class<?> clazz = obj.getClass();
        Field[] allFields = clazz.getDeclaredFields();
        // 定义一个map用于存放列的序号和field.
        ProcessForm processForm = new ProcessForm();
        for (int col = 0; col < allFields.length; col++) {
            Field field = allFields[col];
            Process process = field.getAnnotation(Process.class);
            if (process != null) {
                // 设置类的私有字段属性可访问.
                field.setAccessible(true);
                Object value = null;
                try {
                    value = field.get(obj);
                } catch (IllegalAccessException e) {
                    throw new DingException("审批流:获取属性值错误");
                }
                if (value != null) {
                    if(value instanceof String){
                        if(StrUtil.isBlank(String.valueOf(value))){
                            continue;
                        }
                    }

                    // 取得表单类型
                    ProcessFormType formType = process.formType();
                    if(ProcessFormType.DDDateField.equals(formType)){
                        Date val = (Date) value;
                        value = DateUtil.formatDate(val);
                    }else if(ProcessFormType.DDPhotoField.equals(formType)){
                        String val = String.valueOf(value);
                        String[] imgUrls = val.split(";");
                        value = JSONUtil.toJsonStr(imgUrls);
                    }else if(ProcessFormType.DDAttachment.equals(formType)){
                        String val = String.valueOf(value);
                        String[] files = val.split(";");
                        JSONArray array = new JSONArray();
                        for (String file : files) {
                            JSONObject attachmentJson  = JSONUtil.parseObj(file);
                            array.add(attachmentJson);
                        }
                        value = array.toString();
                    }else if(ProcessFormType.TableField.equals(formType)){
                        if(value instanceof List){
                            // 子组件
                            List list = (ArrayList)value;
                            List childrens = new ArrayList();
                            for (Object o : list) {
                                ProcessForm childrenProcessForm = convert(o);
                                childrens.add(childrenProcessForm.getList().toArray());
                            }
                            value = JSONUtil.toJsonStr(childrens);
                        }
                    }

                    if (StrUtil.isNotEmpty(process.readConverterExp())) {
                        try {
                            value = reverseByExp(String.valueOf(value), process.readConverterExp());
                        } catch (Exception e) {
                            throw new DingException("审批流:类型转换错误");
                        }
                    }

                    String valStr = String.valueOf(value);
                    if (StrUtil.isNotBlank(valStr)) {
                        processForm.put(process.name(), valStr);
                        log.info("name={},value={}", process.name(), valStr);
                    }
                }
            }
        }
        return processForm;
    }


    /**
     * 反向解析值 男=0,女=1,未知=2
     *
     * @param propertyValue 参数值
     * @param converterExp  翻译注解
     * @return 解析后值
     */
    public static String reverseByExp(String propertyValue, String converterExp){
        try {
            String[] convertSource = converterExp.split(",");
            for (String item : convertSource) {
                String[] itemArray = item.split("=");
                if (itemArray[0].equals(propertyValue)) {
                    return itemArray[1];
                }
            }
        } catch (Exception e) {
            log.error("反向解析值失败:{}",e.getMessage());
            throw new DingException("反向解析值失败");
        }
        return propertyValue;
    }


}
